﻿@page
@model IndexModel
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
    ViewData["Title"] = "Configuration Sample";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-8">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Configuration key-value pairs</h2>
            </div>
            <div class="panel-body">
                <p>The app's configuration contains the following key-value pairs. Because the Environment Variable Configuration Provider (<code>AddEnvironmentVariables</code>) is used without a prefix filter, all of the system's environment variables are included in the app's configuration. Therefore, this Index page filters the configuration values before displaying them here.</p>
                <p><code>Logging</code> and <code>Logging:LogLevel</code> are sections, so values aren't provided.</p>
                <ul>
                    @foreach(var kvp in Model.FilteredConfiguration)
                    {
                        <li>@kvp.Key : @kvp.Value</li>
                    }
                </ul>
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="col-md-8">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Bind to a POCO class</h2>
            </div>
            <div class="panel-body">
                <p>Configuration is provided to the app from the <em>starship.json</em> file using a File Configuration Provider (<code>AddJsonFile</code>):</p>
                <pre><code>{
  "starship": {
    "name": "USS Enterprise",
    "registry": "NCC-1701",
    "class": "Constitution",
    "length": 304.8,
    "commissioned": false
  },
  "trademark": "USS Enterprise® Paramount Pictures Corp. http://www.paramount.com"
}</code></pre>
                <p>The app has a <code>Starship</code> model POCO class:</p>
                <pre><code>public class Starship
{
    public string Name { get; set; }
    public string Registry { get; set; }
    public string Class { get; set; }
    public int Length { get; set; }
    public bool Commissioned { get; set; }
}</code></pre>
                <p>Using the <code>GetSection</code> and <code>Bind</code> methods, the configuration is bound to the POCO class:</p>
                <pre><code>public Starship Starship { get; private set; }
...
var starship = new Starship();
_config.GetSection("starship").Bind(starship);
Starship = starship;</code></pre>
                <p>The page model's <code>Starship</code> property displays the bound data using <code>@Model.Starship.&lt;Property&gt;</code> Razor syntax:</p>
                <ul>
                    <li>Name: @Model.Starship.Name</li>
                    <li>Registry: @Model.Starship.Registry</li>
                    <li>Class: @Model.Starship.Class</li>
                    <li>Length: @Model.Starship.Length</li>
                    <li>Commissioned: @Model.Starship.Commissioned</li>
                </ul>
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="col-md-8">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Bind to a POCO class object graph</h2>
            </div>
            <div class="panel-body">
                <p>Configuration is provided to the app from the <em>tvshow.xml</em> file using a File Configuration Provider (<code>AddXmlFile</code>):</p>
                <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;configuration&gt;
  &lt;tvshow&gt;
    &lt;metadata&gt;
      &lt;series&gt;Dr. Who&lt;/series&gt;
      &lt;title&gt;The Sun Makers&lt;/title&gt;
      &lt;airdate&gt;11/26/1977&lt;/airdate&gt;
      &lt;episodes&gt;4&lt;/episodes&gt;
    &lt;/metadata&gt;
    &lt;actors&gt;
        &lt;names&gt;Tom Baker, Louise Jameson, John Leeson&lt;/name&gt;
    &lt;/actors&gt;
    &lt;legal&gt;©1977 BBC http://www.bbc.co.uk/doctorwho/classic/episodeguide/sunmakers/detail.shtml&lt;/legal&gt;
  &lt;/tvshow&gt;
&lt;/configuration&gt;</code></pre>
                <p>The app has a <code>TVShow</code> model POCO class object graph:</p>
                <pre><code>public class TvShow
{
    public Metadata Metadata { get; set; }
    public Actors Actors { get; set; }
    public string Legal { get; set; }
}

public class Metadata
{
    public string Series { get; set; }
    public string Title { get; set; }
    public DateTime AirDate { get; set; }
    public int Episodes { get; set; }
}

public class Actors
{
    public string Names { get; set; }
}</code></pre>
                <p>Using the <code>GetSection</code> and <code>Bind</code> methods, the configuration is bound to the POCO class object model:</p>
                <pre><code>public TvShow TvShow { get; private set; }
...
var tvShow = new TvShow();
_config.GetSection("tvshow").Bind(tvShow);
TvShow = tvShow;</code></pre>
                <p>The page model's <code>TvShow</code> property displays the bound data:</p>
                <ul>
                    <li>Series: @Model.TvShow.Metadata.Series</li>
                    <li>Title: @Model.TvShow.Metadata.Title</li>
                    <li>AirDate: @Model.TvShow.Metadata.AirDate</li>
                    <li>Episodes: @Model.TvShow.Metadata.Episodes</li>
                    <li>Actors:  @Model.TvShow.Actors.Names</li>
                </ul>
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="col-md-8">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Custom Entity Framework Configuration Provider</h2>
            </div>
            <div class="panel-body">
                <p>This sample app demonstrates how to create a basic configuration provider, <code>EFConfigurationProviver</code>, that reads configuration key-value pairs from a database using <a href="https://docs.microsoft.com/ef/core/">Entity Framework (EF) Core</a>. Keys are case insensitive.</p>
                <p>The following quotes are stored in configuration using the custom provider and rendered here:</p>
                <ul>
                    <li>Quote1: @Configuration["quote1"]</li>
                    <li>Quote2: @Configuration["quote2"]</li>
                    <li>Quote3 (key: &quot;quote3&quot;): @Configuration["quote3"]</li>
                    <li>Quote3 (key: &quot;QuOtE3&quot;): @Configuration["QuOtE3"]</li>
                </ul>
                <p>Quotes &copy;2005 Universal Pictures: <a href="https://www.uphe.com/movies/serenity">Serenity</a></p>
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="col-md-8">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Bound array</h2>
            </div>
            <div class="panel-body">
                <p>A Memory Configuration Provider loads a dictionary of configuration key-value pairs that contain array data in the <code>Program</code> class:</p>
                <pre><code>public static Dictionary&lt;string, string&gt; arrayDict = new Dictionary&lt;string, string&gt;
{
    {"array:entries:0", "value0"},
    {"array:entries:1", "value1"},
    {"array:entries:2", "value2"},
    {"array:entries:4", "value4"},
    {"array:entries:5", "value5"}
};</code></pre>
                <pre><code>config.AddInMemoryCollection(arrayDict);</code></pre>
                <p>An <code>ArrayExample</code> class is avaiable to hold the array data:</p>
                <pre><code>public class ArrayExample
{
    public string[] Entries { get; set; }
}</code></pre>
                <p>The class is bound to the configuration data held in the <code>array</code> section. The configuration key index values are enumerated by the configuration binder to create array entries in the class.</p>
                <pre><code>ArrayExample = _config.GetSection("array").Get&lt;ArrayExample&gt;();</code></pre>
                <p>The bound data is rendered in the output:</p>
                <pre><code>@@for (int i = 0; i &lt; Model.ArrayExample.Entries.Length; i++) 
{
    &lt;tr&gt;&lt;td&gt;@@i&lt;/td&gt;&lt;td&gt;@@Model.ArrayExample.Entries[i]&lt;/td&gt;&lt;/tr&gt;
}</code></pre>
                <div class="table-responsive">
                    <table class="table table-striped">
                        <thead><tr><th scope="col">ArrayExample.Entries Array Index</th><th scope="col">ArrayExample.Entries Value</th></tr></thead>
                        <tbody>
                            @for (int i = 0; i < Model.ArrayExample.Entries.Length; i++) 
                            {
                                <tr><td>@i</td><td>@Model.ArrayExample.Entries[i]</td></tr>
                            }
                        </tbody>
                    </table>
                </div>
                <p>There's no direct relationship between the configuration key index values and the array index values. The configuration keys are enumerated, and the configuration values are loaded into the class instance sequentially. A null value isn't created by the configuration binder when the configuration data is read and an index isn't present. In this example, no index &num;3 exists in the configuration data array. The configuration binder assigns the configuration data for configuration key array index &num;4 to the POCO class array in <code>Entries</code> at index &num;3.</p>
                <p>In a second example of binding an array, the sample app includes a JSON settings file, <em>json_array.json</em>, that contains an array:</p>
                <pre><code>{
  "json_array": {
    "key": "valueA",
    "subsection": [
      "valueB",
      "valueC",
      "valueD"
    ]
  }
}</code></pre>
                <p>Configuration loads the contents of this file into key-value pairs.</p>
                <table class="table table-striped">
                    <thead><tr><th scope="col">Key</th><th scope="col">Value</th></tr></thead>
                    <tbody>
                        <tr><td>json_array:key</td><td>valueA</td></tr>
                        <tr><td>json_array:subsection:0</td><td>valueB</td></tr>
                        <tr><td>json_array:subsection:1</td><td>valueC</td></tr>
                        <tr><td>json_array:subsection:2</td><td>valueD</td></tr>
                    </tbody>
                </table>
                <p>The configuration section, <code>json_array</code>, is bound to a POCO class:</p>
                <pre><code>public class JsonArrayExample
{
    public string Key { get; set; }
    public string[] Subsection { get; set; }
}</code></pre>
                <pre><code>JsonArrayExample = _config.GetSection("json_array").Get&lt;JsonArrayExample&gt;();</code></pre>
                <p>The instance can be read and rendered in the output:</p>
                <pre><code>JsonArrayExample.Key</code>: @@Model.JsonArrayExample.Key

@@for (int i = 0; i &lt; Model.JsonArrayExample.Subsection.Length; i++) 
{
    &lt;tr>&lt;td>@@i&lt;/td&gt;&lt;td&gt;@@Model.JsonArrayExample.Subsection[i]&lt;/td&gt;&lt;/tr&gt;
}</code></pre>
                <p><code>JsonArrayExample.Key</code>: @Model.JsonArrayExample.Key</p>
                <div class="table-responsive">
                    <table class="table table-striped">
                        <thead><tr><th scope="col">JsonArrayExample.Subsection Array Index</th><th scope="col">JsonArrayExample.Subsection Value</th></tr></thead>
                        <tbody>
                            @for (int i = 0; i < Model.JsonArrayExample.Subsection.Length; i++) 
                            {
                                <tr><td>@i</td><td>@Model.JsonArrayExample.Subsection[i]</td></tr>
                            }
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
